package com.aierkeji.call.cms.service;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.transaction.Transactional;
import javax.transaction.Transactional.TxType;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import com.aierkeji.call.cms.contants.Contants;
import com.aierkeji.call.cms.dao.jpa.AkjCallClueDao;
import com.aierkeji.call.cms.dao.jpa.AkjCallClueGroupDao;
import com.aierkeji.call.cms.dao.jpa.AkjCallClueHistroyDao;
import com.aierkeji.call.cms.dao.jpa.AkjCallSystemHistoryDao;
import com.aierkeji.call.cms.dao.jpa.AkjCallUserDao;
import com.aierkeji.call.cms.entity.AkjCallClue;
import com.aierkeji.call.cms.entity.AkjCallClueGroup;
import com.aierkeji.call.cms.entity.AkjCallClueHistroy;
import com.aierkeji.call.cms.entity.AkjCallSystemHistory;
import com.aierkeji.call.cms.entity.AkjCallUser;
import com.aierkeji.call.cms.entity.contants.CallResult;
import com.aierkeji.call.cms.entity.contants.CallStatus;
import com.aierkeji.call.cms.entity.contants.Gender;
import com.aierkeji.call.cms.entity.snap.AkjCallUserSnap;
import com.aierkeji.call.cms.entity.vo.AkjCallClueVo;
import com.aierkeji.call.cms.entity.vo.SearchOptionsVo;
import com.aierkeji.call.cms.exception.BatchException;
import com.aierkeji.call.cms.service.AsyncServices.CreateStatic;
import com.aierkeji.call.cms.util.AppConfig;
import com.aierkeji.call.cms.util.CsvUtils;
import com.aierkeji.call.cms.util.DateTimeUtils;
import com.aierkeji.call.cms.util.PageUtils;
import com.aierkeji.call.cms.util.PhoneUtil;
import com.aierkeji.call.cms.util.ResultMapHelper;
import com.aierkeji.call.cms.util.StringUtils;
import com.aierkeji.call.cms.util.ValidataUtil;

@Service
public class AkjCallClueService {
	private final Logger log = LogManager.getLogger(getClass());

	@Value("${upload.clue.max:5000}")
	Integer uploadClueMax;

	@Value("${group.clue.max:100000}")
	Integer gourpClueMax;
	@Autowired
	private AkjCallClueGroupDao akjCallClueGroupDao;
	@Autowired
	private AkjCallClueDao akjCallClueDao;
	@Autowired
	private AkjCallUserDao akjCallUserDao;
	@Autowired
	private AsyncServices asyncServices;

	@Autowired
	private AkjCallClueHistroyDao akjCallClueHistroyDao;

	private String[] downLoadTempleteArr = { "姓名", "电话号码", "性别", "备注" };
	@Autowired
	AkjCallFuntionService akjCallFuntionService;
	@Autowired
	private AkjCallSystemHistoryDao akjCallSystemHistoryDao;

	public Map<String, Object> uploadFile(MultipartFile file, String id) {
		// TODO Auto-generated method stub
		if (file == null || StringUtils.isEmpty(id)) {
			return ResultMapHelper.nullParamsResult();
		}
		Subject subject = SecurityUtils.getSubject();

		AkjCallUser akjCallUser = (AkjCallUser) subject.getSession().getAttribute("loginUser");
		AkjCallClueGroup akjCallClueGroup = akjCallClueGroupDao
				.findByCreatedByAndIsDeleteAndId(AkjCallUserSnap.build(akjCallUser), false, Long.parseLong(id + ""));
		if (akjCallClueGroup == null) {
			return ResultMapHelper.nullParamsResult();
		}

		InputStream is;
		try {
			is = file.getInputStream();

			BufferedReader bf = new BufferedReader(new InputStreamReader(is, "GBK"));
			String line = "";
			List<String> list = new ArrayList<>();
			int listSize = -1;
			while ((line = bf.readLine()) != null) {
				if (!StringUtils.isEmpty(line)) {
					list.add(line.trim());
					listSize++;
					if (listSize > uploadClueMax) {
						list.clear();
						break;
					}

				}
			}
			bf.close();
			if (listSize > uploadClueMax) {
				return ResultMapHelper.failure("超过可导入最大条数:" + uploadClueMax);
			}

			int incorrectPhone = 0;
			if (!CollectionUtils.isEmpty(list)) {
				int groupClueCount = akjCallClueDao.countByClueGroup(akjCallClueGroup);
				if ((groupClueCount + listSize) > gourpClueMax) {
					return ResultMapHelper.failure(
							"超过分组可导入最大条数:" + gourpClueMax + ",\r\n分组已导入" + groupClueCount + "条 ,\r\n本次导入" + listSize);
				}

				Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now());
				List<AkjCallClue> updateResultList = new ArrayList<>(list.size());
				for (int index = 0; index < list.size(); index++) {
					if (index == 0) {
						continue;
					}
					line = list.get(index);
					String[] columnArr = line.split(CsvUtils.getCsvColumnSeparator(), downLoadTempleteArr.length);
					if (columnArr.length != downLoadTempleteArr.length || StringUtils.isEmpty(columnArr[1])) {
						updateResultList.clear();
						return ResultMapHelper.failure("CSV格式错误");
					}
					if (!ValidataUtil.isMobilePhone(columnArr[1])) {
						incorrectPhone++;
						continue;
					}
					AkjCallClue akjCallClue = new AkjCallClue();
					akjCallClue.setName(columnArr[0]);
					akjCallClue.setPhone(columnArr[1]);
					akjCallClue.setCity(PhoneUtil.getCity(akjCallClue.getPhone()));
					try {
						Gender g = Gender.valueOf(columnArr[2]);
						akjCallClue.setGender(g);
					} catch (Exception e) {
						// TODO: handle exception
						log.info("incorrect Gender:{}", columnArr[2]);
					}
					akjCallClue.setCreatedBy(AkjCallUserSnap.build(akjCallUser));
					akjCallClue.setCreatedAt(timestamp);
					akjCallClue.setClueGroup(akjCallClueGroup);
					akjCallClue.setRemark(StringUtils.isEmpty(columnArr[3]) ? null : columnArr[3]);
					updateResultList.add(akjCallClue);
				}

				if (!CollectionUtils.isEmpty(updateResultList)) {

					try {
						int count = akjCallClueDao.batchSave(updateResultList);
						log.info("batch save count :{}", count);
						Map<String, Object> successDataMap = ResultMapHelper.initMap();
						successDataMap.put("saveCount", count);
						successDataMap.put("incorrectPhoneCount", incorrectPhone);
						if (count > 0) {
							akjCallClueGroup.setIsCheckedDuplicate(false);
							this.akjCallClueGroupDao.save(akjCallClueGroup);
						}
						String content = akjCallUser.getName() + "于"
								+ DateTimeUtils.converTimestampToString(DateTimeUtils.getCurrentTime()) + "对分组【"
								+ akjCallClueGroup.getGroupName() + "】上传了" + count + "条线索";
						this.saveLog(content, akjCallUser.getId());
						return ResultMapHelper.success(successDataMap);

					} catch (BatchException e) {
						// TODO: handle exception
						if (e.getSuccessCount() > 0) {
							akjCallClueGroup.setIsCheckedDuplicate(false);
							this.akjCallClueGroupDao.save(akjCallClueGroup);
							String content = akjCallUser.getName() + "于"
									+ DateTimeUtils.converTimestampToString(DateTimeUtils.getCurrentTime()) + "对分组【"
									+ akjCallClueGroup.getGroupName() + "】上传了" + e.getSuccessCount() + "条线索";
							this.saveLog(content, akjCallUser.getId());
						}

						String msg = "数据格式有误，已保存成功" + e.getSuccessCount() + "条";
						return ResultMapHelper.failure(msg);
					}

				} else {
					Map<String, Object> successDataMap = ResultMapHelper.initMap();
					successDataMap.put("saveCount", 0);
					successDataMap.put("incorrectPhoneCount", incorrectPhone);
					return ResultMapHelper.success(successDataMap);
				}
			} else {
				return ResultMapHelper.failure("导入文件内容为空");

			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			log.info("", e);
			return ResultMapHelper.failure("导入文件失败");

		}
	}

	public Page<AkjCallClueVo> query(Integer pageNo, Map<String, Object> request) {
		// TODO Auto-generated method stub
		Subject subject = SecurityUtils.getSubject();
		AkjCallUser akjCallUser = (AkjCallUser) subject.getSession().getAttribute("loginUser");
		if (akjCallUser.checkRole(Contants.ROLE_ID_MANAGER)) {
			request.put("createdBy", akjCallUser.getId());
		} else if (akjCallUser.checkRole(Contants.ROLE_ID_SALES)) {
			request.put("assigneTo", akjCallUser.getId() + "");
		}
		Page<AkjCallClueVo> page = this.akjCallClueDao.query(pageNo, request, Contants.PAGE_SIZE);
		return page;
	}

	@Transactional
	public Map<String, Object> delete(Map<String, Object> map) {
		// TODO Auto-generated method stub
		List<Integer> ids = (List<Integer>) map.get("ids");
		Integer groupId = (Integer) map.get("groupId");
		Subject subject = SecurityUtils.getSubject();
		AkjCallUser akjCallUser = (AkjCallUser) subject.getSession().getAttribute("loginUser");
		int count = 0;
		if (groupId != null && groupId > 0) {

			AkjCallClueGroup akjCallClueGroup = akjCallClueGroupDao.findByCreatedByAndIsDeleteAndId(
					AkjCallUserSnap.build(akjCallUser), false, Long.parseLong(groupId + ""));
			count = akjCallClueDao.deleteByClueGroup(akjCallClueGroup);

			String content = akjCallUser.getName() + "于"
					+ DateTimeUtils.converTimestampToString(DateTimeUtils.getCurrentTime()) + "删除了分组【"
					+ akjCallClueGroup.getGroupName() + "】下的所有线索" + count + "条";
			this.saveLog(content, akjCallUser.getId());
		} else if (!CollectionUtils.isEmpty(ids)) {
			Long[] queryIds = new Long[ids.size()];
			queryIds = ids.stream().map(k -> Long.parseLong(k + "")).toArray(Long[]::new);
			count = akjCallClueDao.deleteClueByIds(queryIds, AkjCallUserSnap.build(akjCallUser));
			String content = akjCallUser.getName() + "于"
					+ DateTimeUtils.converTimestampToString(DateTimeUtils.getCurrentTime()) + "删除了线索" + count + "条";
			this.saveLog(content, akjCallUser.getId());
		}
		return ResultMapHelper.success(count);
	}

	@Transactional
	public Map<String, Object> checkDuplicate(Long groupId) {
		// TODO Auto-generated method stub
		Subject subject = SecurityUtils.getSubject();
		AkjCallUser akjCallUser = (AkjCallUser) subject.getSession().getAttribute("loginUser");
		AkjCallClueGroup akjCallClueGroup = akjCallClueGroupDao
				.findByCreatedByAndIsDeleteAndId(AkjCallUserSnap.build(akjCallUser), false, groupId);
		if (akjCallClueGroup == null) {
			return ResultMapHelper.failure("无效参数！");
		}
		int count = akjCallClueDao.deleteDuplicate(groupId);
		Map<String, Object> successData = new HashMap<String, Object>();
		successData.put("count", count);
		akjCallClueGroup.setIsCheckedDuplicate(true);
		return ResultMapHelper.success(successData);
	}

	public Map<String, Object> assigne(Long groupId) {
		// TODO Auto-generated method stub
		if (groupId == null || groupId < 0) {
			return ResultMapHelper.nullParamsResult();
		}
		Subject subject = SecurityUtils.getSubject();
		AkjCallUser akjCallUser = (AkjCallUser) subject.getSession().getAttribute("loginUser");
		AkjCallClueGroup akjCallClueGroup = akjCallClueGroupDao
				.findByCreatedByAndIsDeleteAndId(AkjCallUserSnap.build(akjCallUser), false, groupId);
		if (akjCallClueGroup == null) {
			return ResultMapHelper.failure("无效参数！");
		}

		int count = akjCallClueDao.countNoAssigned(AkjCallUserSnap.build(akjCallUser), akjCallClueGroup);
		if (count == 0) {
			return ResultMapHelper.failure("没有可分配的线索");
//
		}
		if (akjCallClueGroup.getIsCheckedDuplicate() == null || !akjCallClueGroup.getIsCheckedDuplicate()) {
			return ResultMapHelper.failure("分配前请先对线索进行查重!");
		}
		List<SearchOptionsVo> assigneTos = akjCallUserDao.findCanAssigneUser(akjCallUser.getId());
		Map<String, Object> data = new HashMap<String, Object>();
		data.put("count", count);
		data.put("assigneTos", assigneTos);
		return ResultMapHelper.success(data);
	}

	private void saveLog(String content, Long id) {
		AkjCallSystemHistory akjCallSystemHistory = new AkjCallSystemHistory(content, id);
		akjCallSystemHistoryDao.save(akjCallSystemHistory);
	}

	public Map<String, Object> assigne(Map<String, Object> request) {
		// TODO Auto-generated method stub
		List<String> ids = (List<String>) request.get("ids");
		String clueCountStr = (String) request.get("count");
		Integer clueCount = StringUtils.isEmpty(clueCountStr) ? null : Integer.parseInt(clueCountStr);
		Integer groupId = (Integer) request.get("groupId");
		if (CollectionUtils.isEmpty(ids) || clueCount == null || clueCount <= 0 || groupId == null || groupId <= 0) {
			return ResultMapHelper.nullParamsResult();
		}
//		if (ids.size() > clueCount) {
//			return ResultMapHelper.failure("选择分配的下级数量超过选择分配线索的数量，请重新选择。");
//		}
		Subject subject = SecurityUtils.getSubject();
		AkjCallUser akjCallUser = (AkjCallUser) subject.getSession().getAttribute("loginUser");
		AkjCallClueGroup akjCallClueGroup = akjCallClueGroupDao
				.findByCreatedByAndIsDeleteAndId(AkjCallUserSnap.build(akjCallUser), false, groupId * 1L);
		if (akjCallClueGroup == null) {
			return ResultMapHelper.failure("无效参数！");
		}
		Pageable pageable = PageUtils.buildPageRequestNoSort(1, 1);
		Page<Long> page = akjCallClueDao.getNoAssigendId(AkjCallUserSnap.build(akjCallUser), akjCallClueGroup,
				pageable);
		if (page.getTotalElements() < clueCount * ids.size()) {
			pageable = null;
			return ResultMapHelper.failure("分配条数超过最大可分配条数，请重新选择。");
		}
		int onceMaxSubUserCount = Integer.parseInt(AppConfig.getProperty("assigneOneMaxCount", "3"));// 一次最多可以查询多少个坐席分配的线索
		int multipleCount = ids.size() / onceMaxSubUserCount;
		if (ids.size() % onceMaxSubUserCount > 0) {
			multipleCount = multipleCount + 1;
		}
		pageable = PageUtils.buildPageRequestNoSort(1, onceMaxSubUserCount * clueCount);
		page = akjCallClueDao.getNoAssigendId(AkjCallUserSnap.build(akjCallUser), akjCallClueGroup, pageable);
		List<Long> clueIds = page.getContent();
		int successCount = 0;
		List<CreateStatic> createStaticList = new ArrayList<>();
		for (int v = 1; v <= multipleCount; v++) {
			List<String> subUserList = null;
			if (v == multipleCount) {
				subUserList = ids.subList((v - 1) * onceMaxSubUserCount, ids.size());
			} else {
				subUserList = ids.subList((v - 1) * onceMaxSubUserCount, v * onceMaxSubUserCount);
			}
			pageable = PageUtils.buildPageRequestNoSort(1, subUserList.size() * clueCount);
			page = akjCallClueDao.getNoAssigendId(AkjCallUserSnap.build(akjCallUser), akjCallClueGroup, pageable);
			clueIds = page.getContent();
			List<Long> subList = null;
			for (int i = 0; i < subUserList.size(); i++) {
				if(i==subUserList.size()-1) {
					subList = clueIds.subList(i * clueCount, clueIds.size());
				}else {
					subList = clueIds.subList(i * clueCount, (i + 1) * clueCount);
				}

				try {
					int updateCount = akjCallClueDao.assigneUser(subList, Integer.parseInt(subUserList.get((i))),
							akjCallUser.getId());
					successCount += updateCount;
					AkjCallUser assigneCallUser = new AkjCallUser();
					assigneCallUser.setId(Long.parseLong(subUserList.get((i))));
					createStaticList.add(CreateStatic.build(assigneCallUser, akjCallClueGroup, updateCount));
				} catch (BatchException e) {
					successCount = successCount + e.getSuccessCount();
					log.info("assigne successCount :{}", successCount);
					log.error("assigne error: ", e);
					createStaticList.add(CreateStatic.build(akjCallUser, akjCallClueGroup, e.getSuccessCount()));
					asyncServices.createStatic(createStaticList);
					return ResultMapHelper.failure("分配失败,已分配:" + successCount + "条");
				}
			}
		}
		asyncServices.createStatic(createStaticList);
		Map<String, Object> dataMap = new HashMap<>();
		dataMap.put("successCount", successCount);
		dataMap.put("failureCount", clueCount - successCount);

		return ResultMapHelper.success(dataMap);
	}

	public Map<String, Object> getQueryConifg() {
		Subject subject = SecurityUtils.getSubject();
		AkjCallUser akjCallUser = (AkjCallUser) subject.getSession().getAttribute("loginUser");
		Map<String, Object> data = new HashMap<String, Object>();

		if (akjCallUser.checkRole(Contants.ROLE_ID_ADMIN)) {

			List<SearchOptionsVo> managers = akjCallUserDao.findCanAssigneUser(akjCallUser.getId());
			data.put("managers", managers);
		}
		if (akjCallUser.checkRole(Contants.ROLE_ID_MANAGER)) {
			List<SearchOptionsVo> assigneTos = akjCallUserDao
					.findCanAssigneUser(akjCallUser.checkRole(Contants.ROLE_ID_ADMIN) ? null : akjCallUser.getId());
			data.put("assigneTos", assigneTos);

			List<SearchOptionsVo> groups = akjCallClueGroupDao.findSelectCallClueGroup(
					akjCallUser.checkRole(Contants.ROLE_ID_ADMIN) ? new AkjCallUser() : akjCallUser);
			data.put("groups", groups);
		}
		data.put("callStatus", CallStatus.changeSearchOptionVo());
		data.put("callResult", CallResult.changeSearchOptionVo());

		return ResultMapHelper.success(data);
	}

	public Map<String, Object> download(Map<String, Object> paramMap) {
		// TODO Auto-generated method stub
		Subject subject = SecurityUtils.getSubject();
		AkjCallUser akjCallUser = (AkjCallUser) subject.getSession().getAttribute("loginUser");
		if (akjCallUser.checkRole(Contants.ROLE_ID_MANAGER)) {
			paramMap.put("createdBy", akjCallUser.getId());
		} else if (akjCallUser.checkRole(Contants.ROLE_ID_SALES)) {
			paramMap.put("assigneTo", "" + akjCallUser.getId());
		}
		Long maxCount = Long.parseLong(AppConfig.getProperty("max.download", Contants.defaultReportCount));

		Page<AkjCallClueVo> page = this.akjCallClueDao.query(1, paramMap, 5000);
		if (page.getTotalElements() > maxCount) {
			log.info("count:{},maxCount:{}", page.getTotalElements(), maxCount);
			return ResultMapHelper.failure("数据超过最大记录:" + maxCount + "请重新筛选下载。");
		} else {
			return ResultMapHelper.success(akjCallFuntionService.writeClueCsvString.apply(page.getContent()));
		}
	}

	public Map<String, Object> history(Long clueId) {
		if (clueId == null || clueId <= 0) {
			return ResultMapHelper.nullParamsResult();
		}
		List<AkjCallClueHistroy> list = akjCallClueHistroyDao.findByClueId(clueId);
		return ResultMapHelper.success(list);
	}

	/**
	 * 会对少于当天所有已分配但未拨打的线索进行回收。
	 */
	@Transactional
	public void assigneRecycle() {
		// TODO Auto-generated method stub
		List<SearchOptionsVo> managerList = akjCallUserDao.findUserByRoleId(Contants.ROLE_ID_MANAGER);// 获取所有的企业管理员
		Date assgineDate = DateTimeUtils.getStartTimeOfDay(new Date());
		if (!CollectionUtils.isEmpty(managerList)) {
			managerList.forEach(k -> {
				int count = akjCallClueDao.assigneRecycle(DateTimeUtils.getCurrentTime(), assgineDate,
						Long.parseLong(k.getValue()));
				log.info("assgineDate :{} count :{}", assgineDate, count);
				String content = "系统于：" + DateTimeUtils.converTimestampToString(DateTimeUtils.getCurrentTime())
						+ "回收了线索" + count + "条";
				this.saveLog(content, Long.parseLong(k.getValue()));
			});

		}
	}

	public void assigneBackUps() {
		// TODO Auto-generated method stub
		this.assigneBackUps(null);
	}
	public void assigneBackUps(Date date) {
		// TODO Auto-generated method stub
		List<SearchOptionsVo> managerList = akjCallUserDao.findUserByRoleId(Contants.ROLE_ID_MANAGER);// 获取所有的企业管理员
		log.info("managerList size :{}", managerList.size());
		if (!CollectionUtils.isEmpty(managerList)) {
			managerList.forEach(k -> {
				AkjCallBackupsService akjCallBackupsService = new AkjCallBackupsService(this.akjCallClueDao,
						Long.parseLong(k.getValue()),date);
				log.info("start for id:{},label:{}", k.getValue(), k.getValue());
				akjCallBackupsService.start();
			});
		}
	}

	public Map<String, Object> getQueryConifg(long managerId) {      
		// TODO Auto-generated method stub
		Map<String, Object> data = new HashMap<String, Object>();
		List<SearchOptionsVo> assigneTos = akjCallUserDao.findCanAssigneUser(managerId);
		data.put("assigneTos", assigneTos);

		AkjCallUser createdBy = new AkjCallUser();
		createdBy.setId(managerId);
		List<SearchOptionsVo> groups = akjCallClueGroupDao.findSelectCallClueGroup(createdBy);
		data.put("groups", groups);
		return ResultMapHelper.success(data);
	}

}
